package com.example.nio.tranport.mina.client;

import com.example.nio.tranport.Endpoint;
import com.example.nio.tranport.mina.keepAlive.MinaKeepAliveMessageFactory;
import lombok.Data;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.*;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.Map;

@Data
public class MinaClient implements Endpoint, Client {

    Logger logger = LoggerFactory.getLogger(getClass());

    private NioSocketConnector connector;

    private String host;

    private int port;

    private IoSession ioSession;

    private IoHandler ioHandler;

    private MinaKeepAliveMessageFactory keepAliveMessageFactory;

    private IoServiceListener ioServiceListener = new IoServiceListener() {

        @Override
        public void serviceActivated(IoService service) throws Exception {

        }

        @Override
        public void serviceIdle(IoService service, IdleStatus idleStatus) throws Exception {
            logger.warn("server serviceIdle ...");
        }

        @Override
        public void serviceDeactivated(IoService service) throws Exception {
            logger.warn("server 已经掉线 ...");
        }

        @Override
        public void sessionCreated(IoSession session) throws Exception {

        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {

        }

        @Override
        public void sessionDestroyed(IoSession session) throws Exception {

        }
    };

    public MinaClient(String host, int port, IoHandler ioHandler) {
        this.host = host;
        this.port = port;
        this.ioHandler = ioHandler;
        this.keepAliveMessageFactory = new MinaKeepAliveMessageFactory();
    }

    @Override
    public void init() throws Exception {
        this.connector = new NioSocketConnector();
        this.connector.setConnectTimeoutCheckInterval(5000);
        this.connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
        this.connector.getSessionConfig().setReadBufferSize(1024 * 2);
        this.connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
        this.connector.getFilterChain().addLast("heartbeat", new KeepAliveFilter(keepAliveMessageFactory));
        this.connector.setHandler(ioHandler);
        this.connector.addListener(ioServiceListener);
    }

    @Override
    public IoSession getIoSession() {
        return this.ioSession;
    }

    @Override
    public void start() throws Exception {
        ConnectFuture connectFuture = this.connector.connect(new InetSocketAddress(host, port)).awaitUninterruptibly();
        if (connectFuture.isConnected()) {
            this.ioSession = connectFuture.getSession();
            logger.warn("服务端: " + host + ":" + port + " 连接成功");
        } else {
            logger.warn("服务端: " + host + ":" + port + " 连接失败: " + connectFuture.getException());
        }
    }

    @Override
    public void stop() throws Exception {
        this.connector.dispose();
    }

    @Override
    public Map<Long, IoSession> getSessions() {
        return this.connector.getManagedSessions();
    }

}
